// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
#include "pch.h"
#include "SunLocator.h"

using namespace Weathr;

uint32_t DayOfYear()
{
    uint32_t X = 0;
    static Windows::Globalization::Calendar^ c = ref new Windows::Globalization::Calendar();
    c->SetToNow();
    auto m = c->Month;
    auto d = c->Day;
    c->Month = 1;
    c->Day = 1;
    for (int32_t i = 0; i < m - 1; i++)
    {
        X += c->LastDayInThisMonth;
        c->AddMonths(1);
    }
    X += d;
    return X;
}

// Calculates the coordinates on the unit sphere where the sun is directly above the Earth.
DirectX::XMVECTOR SunLocator::GetLocation()
{
    const time_t localTime = time(nullptr);
    tm gmtTime;
    const errno_t err = gmtime_s(&gmtTime, &localTime);
    if (err != 0)
    {
        return DirectX::XMVectorSet(0, 1, 0, 0);
    }
    const int32_t hour = gmtTime.tm_hour;
    const int32_t minute = gmtTime.tm_min;

    // June 21st is the 172nd day of the year, except on leap years.
    const uint32_t june21DayNumber = ((1900 + gmtTime.tm_year) % 4) != 0 ? 172 : 173;

    // Adapted from http://stackoverflow.com/questions/9269454/given-a-datetime-calculate-the-lat-lon-coordinates-where-the-sun-is-directly-ov
    const float L = 23.5f;
    const float b = 365.25f / (2.0f * PI_F);
    auto dayNumber = static_cast<float>(DayOfYear());
    const float Latitude = L * cos((dayNumber - june21DayNumber) / b);
    const float t0 = 0.0f;
    const float time = static_cast<float>(hour + (minute / 60.0f));
    const float Longitude = -(((time - t0) * 360.0f / 24.0f) - 180);
    return LatLon(Latitude, Longitude).ToSphereCoordinates(1.0f);
}
